package com.rf.richfitwheel.workflow.service.impl;

import com.rf.richfitwheel.admin.feignclient.FSysUserService;
import com.rf.richfitwheel.admin.sys.model.User;
import com.rf.richfitwheel.common.contants.Constant;
import com.rf.richfitwheel.common.exception.BusinessException;
import com.rf.richfitwheel.common.utils.DateUtils;
import com.rf.richfitwheel.common.utils.Jacksons;
import com.rf.richfitwheel.common.utils.StringUtils;
import com.rf.richfitwheel.workflow.conf.AppAccess;
import com.rf.richfitwheel.workflow.conf.IamPropertiesConfig;
import com.rf.richfitwheel.workflow.conf.UrlConstant;
import com.rf.richfitwheel.workflow.contants.StationProcessContant;
import com.rf.richfitwheel.workflow.model.TaskPortalTodoSync;
import com.rf.richfitwheel.workflow.service.PortalTodoSendHisService;
import net.sf.json.JSONObject;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author hushouquan
 */
public class PortalTodoSyncThread implements Runnable{
    protected static final Logger log = LoggerFactory.getLogger(PortalTodoSyncThread.class);
    private IamPropertiesConfig iamPropertiesConfig;
    private TaskService taskService;
    private RestTemplate restTemplate;
    private FSysUserService fSysUserService;
    private RepositoryService repositoryService;
    private HistoryService historyService;
    private RuntimeService runtimeService;
    private String syncType;
    private ProcessInstance processInstance;
    private Task taskOld;
    private List<String> receiveUsers;
    private String moduleType;
    private String startUserId;
    private PortalTodoSendHisService portalTodoSendHisService;
    private List<TaskPortalTodoSync> taskListNew;
    public PortalTodoSyncThread(IamPropertiesConfig iamPropertiesConfig, TaskService taskService,
                                RestTemplate restTemplate, FSysUserService fSysUserService,
                                RepositoryService repositoryService, HistoryService historyService,
                                RuntimeService runtimeService, String syncType, ProcessInstance processInstance, Task taskOld,
                                List<String> receiveUsers, String moduleType, String startUserId, PortalTodoSendHisService portalTodoSendHisService,
                                List<TaskPortalTodoSync> taskListNew){
        this.iamPropertiesConfig = iamPropertiesConfig;
        this.taskService = taskService;
        this.restTemplate = restTemplate;
        this.fSysUserService = fSysUserService;
        this.repositoryService = repositoryService;
        this.historyService = historyService;
        this.runtimeService = runtimeService;
        this.syncType = syncType;
        this.processInstance = processInstance;
        this.taskOld = taskOld;
        this.receiveUsers = receiveUsers;
        this.moduleType = moduleType;
        this.startUserId = startUserId;
        this.portalTodoSendHisService = portalTodoSendHisService;
        this.taskListNew = taskListNew;
    }
    
    @Override
    public void run(){
        switch(syncType){
            case "sync":
                runSync();
                break;
            case "update":
                runSyncUpdate();
                break;
            case "first":
                runSyncFirst();
                break;
            case "delete":
                runDelete();
                break;
            case "done":
                runDone();
                break;
            case "deleteAndNew":
                runDeleteAndNew();
                break;
            default:
                break;
        }
    }
    
    /**
     * 同步待办,非首节点新增
     */
    private void runSync(){
        try{
            AppAccess appAccess = getRealAppAccess();
            for(TaskPortalTodoSync task : this.taskListNew){
                Map<String, Object> param = new LinkedHashMap<>();
                param.put("todoTitle", this.processInstance.getName());
                param.put("category", 1);
                param.put("sourceId", task.getTask().getId());
                param.put("appId", appAccess.getAppId());
                param.put("pcUrl", appAccess.getFrontUrl() + StationProcessContant.PORTAL_PROCESS_DETAIL_ROUTE + "?comp=" + task.getTask().getFormKey() + "&taskId=" + task.getTask().getId());
                param.put("secretLevel", 10);
                param.put("urgentLevel", 1);
                param.put("businessType", iamPropertiesConfig.getBusinessTypeByAppId(appAccess.getAppId()));//业务类型，该字段为字典类型，应⽤需要传⼊正确的字典值（由综合⻔户系统提供）
                param.put("limitTime", "2099-12-31 23:59:59");
                User user = fSysUserService.getUserOnly(this.startUserId);
                param.put("sendUserWorkNo", user.getAccountName());
                param.put("sendOrgId", user.getOrgId());
                param.put("sendTime", DateUtils.format(task.getTask().getCreateTime(), DateUtils.DATE_TIME_PATTERN));
                param.put("label", new ArrayList<>());
                param.put("receiveUsers", getReceiveUsers(task.getReceiveUsers()));
                String bodyDataStr = Jacksons.parse(param);
                StringEntity stringEntity = new StringEntity(bodyDataStr, ContentType.APPLICATION_JSON);
                CloseableHttpResponse response = HttpEntityJsonUtil.executeApi(iamPropertiesConfig.getAccessKeyByAppId(appAccess.getAppId()),
                        iamPropertiesConfig.getSecretKeyByAppId(appAccess.getAppId()), appAccess.getAppId(), "POST", stringEntity, Collections.emptyMap(),
                        iamPropertiesConfig.getUrl() + UrlConstant.IAM_PORTAL_TODO_SYNC);
                int statusCode = response.getStatusLine().getStatusCode();
                String result = EntityUtils.toString(response.getEntity());
                String success = Constant.COMMON_YES_OR_NO_NO;
                if(HttpStatus.SC_OK == statusCode){
                    JSONObject jb = JSONObject.fromObject(result);
                    if(jb.containsKey("code") && jb.getInt("code") == HttpStatus.SC_OK){
                        success = Constant.COMMON_YES_OR_NO_YES;
                    }
                }
                //把发送结果存一下
                portalTodoSendHisService.savePortalTodoSendHis(appAccess.getAppId(), appAccess.getAccessKey(),
                        appAccess.getSecretKey(), this.moduleType, appAccess.getBusinessType(), bodyDataStr, "POST",
                        success, 1, UrlConstant.IAM_PORTAL_TODO_SYNC);
                if(HttpStatus.SC_OK != statusCode){
                    log.error("同步待办任务失败{}:{}", statusCode, result);
                    throw new BusinessException("同步待办任务失败:" + statusCode);
                }
                log.info("同步待办任务结果{}:{}", result, bodyDataStr);
            }
        }catch(Exception e){
            log.error("出错了呀", e);
        }
    }
    
    
    /**
     * 修改待办
     */
    private void runSyncUpdate(){
        try{
            AppAccess appAccess = getRealAppAccess();
            ProcessDefinition def = getProcessDefinition(this.processInstance.getProcessDefinitionId());
            for(TaskPortalTodoSync task : this.taskListNew){
                Map<String, Object> param = new LinkedHashMap<>();
                param.put("todoTitle", this.processInstance.getName());
                param.put("category", 1);
                param.put("sourceId", task.getTask().getId());
                param.put("appId", appAccess.getAppId());
                param.put("pcUrl", appAccess.getFrontUrl() + StationProcessContant.PORTAL_PROCESS_DETAIL_ROUTE + "?comp=" + def.getCategory() + "&taskId=" + task.getTask().getId());
                param.put("secretLevel", 10);
                param.put("urgentLevel", 1);
                param.put("businessType", iamPropertiesConfig.getBusinessTypeByAppId(appAccess.getAppId()));//业务类型，该字段为字典类型，应⽤需要传⼊正确的字典值（由综合⻔户系统提供）
                param.put("limitTime", "2099-12-31 23:59:59");
                User user = fSysUserService.getUserOnly(this.startUserId);
                param.put("sendUserWorkNo", user.getAccountName());
                param.put("sendOrgId", user.getOrgId());
                param.put("sendTime", DateUtils.format(task.getTask().getCreateTime(), DateUtils.DATE_TIME_PATTERN));
                param.put("label", new ArrayList<>());
                param.put("receiveUsers", getReceiveUsers(task.getReceiveUsers()));
                String bodyDataStr = Jacksons.parse(param);
                StringEntity stringEntity = new StringEntity(bodyDataStr, ContentType.APPLICATION_JSON);
                CloseableHttpResponse response = HttpEntityJsonUtil.executeApi(iamPropertiesConfig.getAccessKeyByAppId(appAccess.getAppId()),
                        iamPropertiesConfig.getSecretKeyByAppId(appAccess.getAppId()), appAccess.getAppId(), "PUT", stringEntity, Collections.emptyMap(),
                        iamPropertiesConfig.getUrl() + UrlConstant.IAM_PORTAL_TODO_SYNC);
                int statusCode = response.getStatusLine().getStatusCode();
                String result = EntityUtils.toString(response.getEntity());
                String success = Constant.COMMON_YES_OR_NO_NO;
                if(HttpStatus.SC_OK == statusCode){
                    JSONObject jb = JSONObject.fromObject(result);
                    if(jb.containsKey("code") && jb.getInt("code") == HttpStatus.SC_OK){
                        success = Constant.COMMON_YES_OR_NO_YES;
                    }
                }
                //把发送结果存一下
                portalTodoSendHisService.savePortalTodoSendHis(appAccess.getAppId(), appAccess.getAccessKey(),
                        appAccess.getSecretKey(), this.moduleType, appAccess.getBusinessType(), bodyDataStr, "PUT",
                        success, 1, UrlConstant.IAM_PORTAL_TODO_SYNC);
                if(HttpStatus.SC_OK != statusCode){
                    log.error("同步待办任务失败{}:{}", statusCode, result);
                    throw new BusinessException("同步待办任务失败:" + statusCode);
                }
                log.error("修改待办任务结果{}:{}", result, bodyDataStr);
            }
        }catch(Exception e){
            log.error("出错了呀", e);
        }
    }
    
    /**
     * 第一个节点特殊处理
     */
    private void runSyncFirst(){
        try{
            AppAccess appAccess = getRealAppAccess();
            ProcessDefinition def = getProcessDefinition(this.processInstance.getProcessDefinitionId());
            Map<String, Object> param = new LinkedHashMap<>();
            param.put("todoTitle", this.processInstance.getName());
            param.put("category", 1);
            param.put("sourceId", taskOld.getId());
            param.put("appId", appAccess.getAppId());
            param.put("pcUrl", appAccess.getFrontUrl() + StationProcessContant.PORTAL_PROCESS_DETAIL_ROUTE + "?comp=" + def.getCategory() + "&taskId=" + taskOld.getId());
            param.put("secretLevel", 10);
            param.put("urgentLevel", 1);
            param.put("businessType", iamPropertiesConfig.getBusinessTypeByAppId(appAccess.getAppId()));//业务类型，该字段为字典类型，应⽤需要传⼊正确的字典值（由综合⻔户系统提供）
            param.put("limitTime", "2099-12-31 23:59:59");
            User user = fSysUserService.getUserOnly(this.startUserId);
            param.put("sendUserWorkNo", user.getAccountName());
            param.put("sendOrgId", user.getOrgId());
            param.put("sendTime", DateUtils.format(taskOld.getCreateTime(), DateUtils.DATE_TIME_PATTERN));
            param.put("label", new ArrayList<>());
            param.put("receiveUsers", getReceiveUsersFirst(user.getAccountName()));
            String bodyDataStr = Jacksons.parse(param);
            StringEntity stringEntity = new StringEntity(bodyDataStr, ContentType.APPLICATION_JSON);
            CloseableHttpResponse response = HttpEntityJsonUtil.executeApi(iamPropertiesConfig.getAccessKeyByAppId(appAccess.getAppId()),
                    iamPropertiesConfig.getSecretKeyByAppId(appAccess.getAppId()), appAccess.getAppId(), "POST", stringEntity, Collections.emptyMap(),
                    iamPropertiesConfig.getUrl() + UrlConstant.IAM_PORTAL_TODO_SYNC);
            int statusCode = response.getStatusLine().getStatusCode();
            String result = EntityUtils.toString(response.getEntity());
            String success = Constant.COMMON_YES_OR_NO_NO;
            if(HttpStatus.SC_OK == statusCode){
                JSONObject jb = JSONObject.fromObject(result);
                if(jb.containsKey("code") && jb.getInt("code") == HttpStatus.SC_OK){
                    success = Constant.COMMON_YES_OR_NO_YES;
                }
            }
            //把发送结果存一下
            portalTodoSendHisService.savePortalTodoSendHis(appAccess.getAppId(), appAccess.getAccessKey(),
                    appAccess.getSecretKey(), this.moduleType, appAccess.getBusinessType(), bodyDataStr, "POST",
                    success, 1, UrlConstant.IAM_PORTAL_TODO_SYNC);
            if(HttpStatus.SC_OK != statusCode){
                log.error("同步待办任务失败（发起节点）{}:{}", statusCode, result);
                
                throw new BusinessException("同步待办任务失败:" + statusCode);
            }
            log.info("同步待办任务结果（发起节点）{}:{}", result, bodyDataStr);
            
            //把待办置为已办
            Map<String, Object> paramDone = new LinkedHashMap<>();
            paramDone.put("appId", appAccess.getAppId());
            paramDone.put("sourceId", this.taskOld.getId());
            List<Map<String, Object>> recUsers = new ArrayList<>();
            Map<String, Object> mm = new HashMap<>();
            mm.put("workNo", user.getAccountName());
            recUsers.add(mm);
            paramDone.put("receiveUsers", recUsers);
            String bodyDataStrDone = Jacksons.parse(paramDone);
            StringEntity stringEntityDone = new StringEntity(bodyDataStrDone, ContentType.APPLICATION_JSON);
            CloseableHttpResponse responseDone = HttpEntityJsonUtil.executeApi(iamPropertiesConfig.getAccessKeyByAppId(appAccess.getAppId()),
                    iamPropertiesConfig.getSecretKeyByAppId(appAccess.getAppId()), appAccess.getAppId(), "POST", stringEntityDone, Collections.emptyMap(),
                    iamPropertiesConfig.getUrl() + UrlConstant.IAM_PORTAL_TODO_SYNC_DONE);
            int statusCodeDone = responseDone.getStatusLine().getStatusCode();
            String resultDone = EntityUtils.toString(responseDone.getEntity());
            String successDone = Constant.COMMON_YES_OR_NO_NO;
            if(HttpStatus.SC_OK == statusCodeDone){
                JSONObject jb = JSONObject.fromObject(resultDone);
                if(jb.containsKey("code") && jb.getInt("code") == HttpStatus.SC_OK){
                    successDone = Constant.COMMON_YES_OR_NO_YES;
                }
            }
            //把发送结果存一下
            portalTodoSendHisService.savePortalTodoSendHis(appAccess.getAppId(), appAccess.getAccessKey(),
                    appAccess.getSecretKey(), this.moduleType, appAccess.getBusinessType(), bodyDataStrDone, "POST",
                    successDone, 1, UrlConstant.IAM_PORTAL_TODO_SYNC_DONE);
            if(HttpStatus.SC_OK != statusCodeDone){
                log.warn("调用待办置为已办接口失败,{},{}", statusCodeDone, resultDone);
                throw new BusinessException("调用待办置为已办接口失败:" + statusCodeDone);
            }
            log.info("待办置为已办任务结果{}:{}" , resultDone, bodyDataStrDone);
        }catch(Exception e){
            log.error("出错了呀", e);
        }
    }
    private List<Map<String, Object>> getReceiveUsers(Task task){
        List<Map<String, Object>> us = new ArrayList<>();
        if(StringUtils.isNotBlank(task.getAssignee())){
            Map<String, Object> pp = new LinkedHashMap<>();
            User user = fSysUserService.getUserOnly(task.getAssignee());
            if(user == null || StringUtils.isBlank(user.getAccountName())){
                return null;
            }
            pp.put("workNo", user.getAccountName());
            pp.put("isCare", 0);
            us.add(pp);
            return us;
        }
        List<IdentityLink> listId = taskService.getIdentityLinksForTask(task.getId());
        List<String> uGroup = listId.stream().filter(f -> f.getType().equals("candidate")).map(IdentityLink::getGroupId).collect(Collectors.toList());
        return fSysUserService.getUserListByStationIds(String.join(",", uGroup)).stream().map(m ->{
            Map<String, Object> pp = new LinkedHashMap<>();
            User user = fSysUserService.getUserOnly(m.getId());
            if(user == null || StringUtils.isBlank(user.getAccountName())){
                return null;
            }
            pp.put("workNo", user.getAccountName());
            pp.put("isCare", 0);
            return pp;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }
    private Object getReceiveUsers(List<String> receiveUsers){
        return receiveUsers.stream().map(m -> {
            Map<String, Object> pp = new LinkedHashMap<>();
            User user = fSysUserService.getUserOnly(m);
            if(user == null || StringUtils.isBlank(user.getAccountName())){
                return null;
            }
            pp.put("workNo", user.getAccountName());
            pp.put("isCare", 0);
            return pp;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }
    private List<Map<String, Object>> getReceiveUsersFirst(String startUserId){
        List<Map<String, Object>> us = new ArrayList<>();
        Map<String, Object> pp = new LinkedHashMap<>();
        pp.put("workNo", startUserId);
        pp.put("isCare", 1);
        us.add(pp);
        return us;
    }
    
    private HistoricProcessInstance getProcessInstanceHis(String processId){
        return this.historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).unfinished().singleResult();
    }
    
    private ProcessInstance getProcessInstance(String processId){
        return this.runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
    }
    
    private ProcessDefinition getProcessDefinition(String defId){
        return this.repositoryService.getProcessDefinition(defId);
    }
    
    private List<Task> getTasks(String processId){
        return this.taskService.createTaskQuery().processInstanceId(processId).list();
    }
    private AppAccess getRealAppAccess(){
        return iamPropertiesConfig.getAppAccess().stream().filter(m -> m.getModuleType().contains(this.moduleType)).findFirst().get();
    }
    
    /**
     * 删除待办
     */
    private void runDelete(){
        try{
            AppAccess appAccess = getRealAppAccess();
            Map<String, Object> param = new LinkedHashMap<>();
            param.put("appId", appAccess.getAppId());
            param.put("sourceId", this.taskOld.getId());
            param.put("receiveUsers", receiveUsers.stream().map(m -> {
                Map<String, Object> pp = new LinkedHashMap<>();
                User user = fSysUserService.getUserOnly(m);
                if(user == null || StringUtils.isBlank(user.getAccountName())){
                    return null;
                }
                pp.put("workNo", user.getAccountName());
                return pp;
            }).filter(Objects::nonNull).collect(Collectors.toList()));
            String bodyDataStr = Jacksons.parse(param);
            StringEntity stringEntity = new StringEntity(bodyDataStr, ContentType.APPLICATION_JSON);
            CloseableHttpResponse response = HttpEntityJsonUtil.executeApi(iamPropertiesConfig.getAccessKeyByAppId(appAccess.getAppId()),
                    iamPropertiesConfig.getSecretKeyByAppId(appAccess.getAppId()), appAccess.getAppId(), "DELETE", stringEntity, Collections.emptyMap(),
                    iamPropertiesConfig.getUrl() + UrlConstant.IAM_PORTAL_TODO_SYNC_DELETE);
            int statusCode = response.getStatusLine().getStatusCode();
            String result = EntityUtils.toString(response.getEntity());
            String success = Constant.COMMON_YES_OR_NO_NO;
            if(HttpStatus.SC_OK == statusCode){
                JSONObject jb = JSONObject.fromObject(result);
                if(jb.containsKey("code") && jb.getInt("code") == HttpStatus.SC_OK){
                    success = Constant.COMMON_YES_OR_NO_YES;
                }
            }
            //把发送结果存一下
            portalTodoSendHisService.savePortalTodoSendHis(appAccess.getAppId(), appAccess.getAccessKey(),
                    appAccess.getSecretKey(), this.moduleType, appAccess.getBusinessType(), bodyDataStr, "DELETE",
                    success, 1, UrlConstant.IAM_PORTAL_TODO_SYNC_DELETE);
            if(HttpStatus.SC_OK != statusCode){
                log.error("删除待办任务失败{}",response);
                throw new BusinessException("删除待办任务失败:" + statusCode);
            }
            log.info("删除待办任务结果{}:{}" , result, bodyDataStr);
        }catch(Exception e){
            log.error("出错了呀", e);
        }
    }
    
    /**
     * 置为已办
     */
    private void runDone(){
        try{
            AppAccess appAccess = getRealAppAccess();
            Map<String, Object> param = new LinkedHashMap<>();
            param.put("appId", appAccess.getAppId());
            param.put("sourceId", this.taskOld.getId());
            param.put("receiveUsers", receiveUsers.stream().map(m -> {
                Map<String, Object> pp = new LinkedHashMap<>();
                User user = fSysUserService.getUserOnly(m);
                if(user == null || StringUtils.isBlank(user.getAccountName())){
                    return null;
                }
                pp.put("workNo", user.getAccountName());
                return pp;
            }).filter(Objects::nonNull).collect(Collectors.toList()));
            String bodyDataStr = Jacksons.parse(param);
            StringEntity stringEntity = new StringEntity(bodyDataStr, ContentType.APPLICATION_JSON);
            CloseableHttpResponse response = HttpEntityJsonUtil.executeApi(iamPropertiesConfig.getAccessKeyByAppId(appAccess.getAppId()),
                    iamPropertiesConfig.getSecretKeyByAppId(appAccess.getAppId()), appAccess.getAppId(), "POST", stringEntity, Collections.emptyMap(),
                    iamPropertiesConfig.getUrl() + UrlConstant.IAM_PORTAL_TODO_SYNC_DONE);
            int statusCode = response.getStatusLine().getStatusCode();
            String result = EntityUtils.toString(response.getEntity());
            String success = Constant.COMMON_YES_OR_NO_NO;
            if(HttpStatus.SC_OK == statusCode){
                JSONObject jb = JSONObject.fromObject(result);
                if(jb.containsKey("code") && jb.getInt("code") == HttpStatus.SC_OK){
                    success = Constant.COMMON_YES_OR_NO_YES;
                }
            }
            //把发送结果存一下
            portalTodoSendHisService.savePortalTodoSendHis(appAccess.getAppId(), appAccess.getAccessKey(),
                    appAccess.getSecretKey(), this.moduleType, appAccess.getBusinessType(), bodyDataStr, "POST",
                    success, 1, UrlConstant.IAM_PORTAL_TODO_SYNC_DONE);
            if(HttpStatus.SC_OK != statusCode){
                log.warn("调用待办置为已办接口失败,{},{}", statusCode, result);
                throw new BusinessException("调用待办置为已办接口失败:" + statusCode);
            }
            log.info("待办置为已办任务结果{}:{}" , result, bodyDataStr);
        }catch(Exception e){
            log.error("出错了呀", e);
        }
    }
    
    private void runDeleteAndNew(){
        runDelete();
//        runSync();
    }
}
